package cn.xinfei.xdecision.engine.runner.service;

import cn.xinfei.xdecision.common.datamodel.DecisionResult;
import cn.xinfei.xdecision.common.model.datax.datainterface.v2.VariableVO;
import cn.xinfei.xdecision.common.model.enginex.po.Engine;
import cn.xinfei.xdecision.common.model.enginex.po.EngineVersion;
import cn.xinfei.xdecision.common.model.enginex.vo.EngineVersionInOutVarsRespVo;
import cn.xinfei.xdecision.constant.EngineResultEnum;
import cn.xinfei.xdecision.engine.runner.context.BranchTypeEnum;
import cn.xinfei.xdecision.engine.runner.context.PipelineContextHolder;
import cn.xinfei.xdecision.engine.runner.executor.NodeHandler;
import cn.xinfei.xdecision.engine.runner.metadata.MetadataProvider;
import cn.xinfei.xdecision.engine.runner.vo.EngineApiRequest;
import cn.xinfei.xdecision.model.DecisionApiRequest;
import com.google.common.collect.Table;
import io.micrometer.core.instrument.MeterRegistry;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;

@Slf4j
@Service
public class DecisionParamCheckServer {

    @Autowired
    private MetadataProvider metadataProvider;

    @Autowired
    private MeterRegistry meterRegistry;

    @Autowired
    private DecisionResultService decisionResultService;


    /**
     * @param tpCode
     * @param requestId
     * @return DecisionResult幂等校验不通过，被拦截；null通过
     */
    public DecisionResult idempotent(String tpCode, String requestId) {

        try {
            List<DecisionResult> decisionResults = decisionResultService.getDecisionResultByBizId(requestId);
            if (CollectionUtils.isEmpty(decisionResults)) {
                return null;
            }
            Optional<DecisionResult> any = decisionResults.stream().filter(decisionResult -> decisionResult.getTpCode().equals(tpCode) && decisionResult.getBranch().equals(BranchTypeEnum.MAIN.name())).findAny();
            if (any.isPresent()) {
                return any.get();
            }
        } catch (Exception e) {
            log.error("幂等校验异常，默认通过. msg={}", e.getMessage(), e);
        }

        return null;
    }

    /**
     * 校验是否有权限
     */
    public EngineResultEnum checkAuth(DecisionApiRequest apiRequest) {
        Map<Long, Engine> engineList = metadataProvider.getEngineList(apiRequest.getEngineCode());
        Engine engine = engineList.values().stream().findFirst().orElse(new Engine());
        if (!Objects.equals(engine.getOrganId(), apiRequest.getOrganId())) {
            log.warn("请求当前引擎没有权限,engineCode={}，organId={}", apiRequest.getEngineCode(), apiRequest.getOrganId());
            meterRegistry.counter("xengine_decision_checkAuth", "miss", "engine").increment();
            return EngineResultEnum.FAIL_NO_PERMISSION;
        }
        return EngineResultEnum.PROCESSING;
    }


    public EngineResultEnum checkEngine(EngineApiRequest apiRequest) {
        //1.校验决策流是否存在
        String engineCode = apiRequest.getEngineCode();
        Map<String, NodeHandler> engineNodeMap = metadataProvider.getEngineNodeList(engineCode);
        if (null == engineNodeMap || engineNodeMap.size() == 0) {
            log.warn("请求引擎不存在或尚未部署运行,engineCode={}", engineCode);
            meterRegistry.counter("xengine_decision_check", "miss", "engine").increment();
            return EngineResultEnum.NO_EXISTS;
        }
        EngineVersion engineVersion = metadataProvider.getEngineVersion(engineCode);
        Long versionNo = engineVersion.getVersionNo();
        apiRequest.setVersionNo(versionNo);

//        log.info("决策流信息有效,engineCode={},versionNo={}", engineCode, versionNo);
        PipelineContextHolder.setEngineCode(engineCode);
        PipelineContextHolder.setEngineVersion(versionNo + "");
        PipelineContextHolder.setEngineName(engineVersion.getEngineName());
        return EngineResultEnum.PROCESSING;
    }

    public EngineResultEnum checkParam(EngineApiRequest apiRequest) {
        //1.校验决策流是否存在
        Map<String, Object> in = apiRequest.getIn();
        String engineCode = apiRequest.getEngineCode();
        Long versionNo = apiRequest.getVersionNo();
        Table<String, Long, EngineVersionInOutVarsRespVo> inOutVarsCache = MetadataProvider.inOutVarsCache;
        EngineVersionInOutVarsRespVo engineVersionInOutVarsRespVo = inOutVarsCache.get(engineCode, versionNo);
        if (null != engineVersionInOutVarsRespVo) {
            List<VariableVO> inVars = engineVersionInOutVarsRespVo.getInVars();
            Set<String> miss = new HashSet<>();
            inVars.forEach(variableVO -> {
                String varCode = variableVO.getVarCode();
                if (!in.containsKey(varCode)) {
                    miss.add(varCode);
                }
            });
            if (miss.size() > 0) {
                log.warn("上送的输入变量不足，miss={}", miss);
                meterRegistry.counter("xengine_decision_check", "miss", "param").increment(miss.size());
            }
        } else {
            log.warn("决策流输入输出变量为null");
            meterRegistry.counter("xengine_decision_check", "miss", "null").increment();
        }

        return EngineResultEnum.PROCESSING;
    }
}
